package com.sy.olddriver.listener;

import com.sy.olddriver.annotations.RequestMapping;
import com.sy.olddriver.constant.AppConstant;
import com.sy.olddriver.dto.MappingObj;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import java.io.File;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * 项目启动和销毁的监听器
 *
 * @author Administrator
 */
@WebListener
public class AppContextListener implements ServletContextListener {
    /**
     * 在项目初始化的时候完成一些操作
     * 1.对所有的Handler进行统一实例化
     *
     * @param e 事件对象
     * @auth Administrator
     */
    @Override
    public void contextInitialized(ServletContextEvent e) {
        ServletContext ctx = e.getServletContext();

        //1.对所有的Handler对象进行统一实例化并生成处理器方法与其映射的路径信息
        //(1)获取处理器类所在的包
        //com.sy.olddriver.handler
        String handlerPackage = ctx.getInitParameter("handlerPackageName");
        //(2)根据包名得到当前包下所有的处理器类的名字
        //a.获取当前包在操作系统中的文件路径
        //a1.获取运行时候字节码文件的实际路径
        String classPath = Thread.currentThread().getContextClassLoader().getResource("").getPath();
        //a2.将实际的字节码路径和包名拼接，得到最终处理器所在的目录
        String handlerDir = classPath + handlerPackage.replace(".", File.separator);

        //创建一个集合用于存储所有的处理器路径和方法的映射信息
        List<MappingObj> mappingObjList = new ArrayList<>();

        //b.遍历处理器类所在的文件目录，得到所有处理器类对应的class文件
        File[] handlerClassFiles = new File(handlerDir).listFiles();
        if (null != handlerClassFiles) {
            for (File handlerClassFile : handlerClassFiles) {
                //b1.将所有的文件名中的.class去掉，得到最终的类名
                String handlerClassSimpleName = handlerClassFile.getName().replace(".class", "");

                //b2.获取每一个处理器的类的完整类名
                String handlerClassFullName = handlerPackage + "." + handlerClassSimpleName;

                //c.对处理器类进行实例化操作，并且存储所有的处理器方法及其映射信息
                try {
                    Class<?> handlerClass = Class.forName(handlerClassFullName);
                    //对每个处理器类进行实例化
                    Object handlerObj = handlerClass.newInstance();

                    //c1.获取处理器的映射路径
                    //c11.获取处理器类上的注解
                    RequestMapping classRequestMapping = handlerClass.getDeclaredAnnotation(RequestMapping.class);
                    String handlerUrl = "";
                    if (null != classRequestMapping) {
                        //c12.获取注解中的处理器类对应的访问路径
                        handlerUrl = classRequestMapping.value();
                    }

                    //c2.获取每一个方法的访问路径
                    //c21.获取处理器类中的所有方法
                    Method[] handlerMethods = handlerClass.getDeclaredMethods();
                    //c22.遍历所有的处理器方法，获取每一个处理器方法的前面注解中的路径
                    for (Method handlerMethod : handlerMethods) {
                        //c221.获取每个处理器方法前面的注解
                        RequestMapping handlerMethodRequestMapping = handlerMethod.getDeclaredAnnotation(RequestMapping.class);
                        //c222.获取注解中处理器方法的访问路径
                        String handlerMethodUrl = "";
                        if (null != handlerMethodRequestMapping) {
                            handlerMethodUrl = handlerMethodRequestMapping.value();
                            //c223.为每一个处理器方法创建MappingObj对象
                            //该对象中包括了要调用的处理器实例，要调用的方法，及其访问路径
                            MappingObj mappingObj = new MappingObj();
                            mappingObj.setHandlerObj(handlerObj);
                            mappingObj.setHandlerMethod(handlerMethod);
                            mappingObj.setHandlerMethodUrl("/" + handlerUrl + "/" + handlerMethodUrl);
                            //c224.将每次创建的映射对象存入集合
                            mappingObjList.add(mappingObj);
                        }
                    }
                } catch (ClassNotFoundException e1) {
                    e1.printStackTrace();
                    System.out.println("类" + handlerClassFullName + "不存在");
                } catch (IllegalAccessException e1) {
                    e1.printStackTrace();
                } catch (InstantiationException e1) {
                    e1.printStackTrace();
                    System.out.println("类" + handlerClassFullName + "实例化失败");
                }

            }
        }
        //为了能够在DispatcherServlet中使用此处生成的映射对象
        //将映射信息存入Servlet上下文对象中，使其能够共享
        ctx.setAttribute(AppConstant.MAPPING_OBJS_SERVLET_CONTEXT_KEY, mappingObjList);




    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {

    }
}
